package com.ym.manager.yinsheng.util;

import javax.crypto.Cipher;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.*;

public class SignUtils {

	// 缓存公钥和私钥
	public static Map<String, Object> certMap = new java.util.concurrent.ConcurrentHashMap<String, Object>();
	/**
	 * 文件读取缓冲区大小
	 */
	private static final int CACHE_SIZE = 2048;

	/**
	 * 除去数组中的空值和签名参数
	 * 
	 * @param sArray 签名参数组
	 * @return 去掉空值与签名参数后的新签名参数组
	 */
	public static Map<String, String> paraFilter(Map<String, String> sArray) {
		Map<String, String> result = new TreeMap<String, String>();
		if (sArray == null || sArray.size() <= 0) {
			return result;
		}
		for (String key : sArray.keySet()) {
			String value = sArray.get(key);
			if (null == value || key.equalsIgnoreCase("sign")) {
				continue;
			}
			result.put(key, value);
		}
		return result;
	}

	/**
	 * 
	 * @param sortedParams
	 * @return
	 */
	public static String getSignContent(Map<String, String> sortedParams) {
		StringBuffer content = new StringBuffer();
		List<String> keys = new ArrayList<String>(sortedParams.keySet());
		Collections.sort(keys);
		int index = 0;
		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			String value = sortedParams.get(key);
			if (StringUtils.areNotEmpty(key, value)) {
				content.append((index == 0 ? "" : "&") + key + "=" + value);
				index++;
			}
		}
		return content.toString();
	}

	public static String rsaSign(String content, String charset, String privateCerPwd,
			InputStream pfxCertFileInputStream, String privateCerPath) throws Exception {
		try {
			PrivateKey priKey = getPrivateKeyFromPKCS12(privateCerPwd, pfxCertFileInputStream, privateCerPath);

			Signature signature = Signature.getInstance("SHA1WithRSA");

			signature.initSign(priKey);

			if (StringUtils.isEmpty(charset)) {
				signature.update(content.getBytes());
			} else {
				signature.update(content.getBytes(charset));
			}

			byte[] signed = signature.sign();

			// String sign = new String(Base64.encodeBase64(signed), charset);
			String sign = new String(Base64Utils.encode(signed));

			return sign;
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception("RSAcontent = " + content + "; charset = " + charset, e);
		}
	}

	/**
	 * 把参数签名
	 *
	 * @param params
	 * @param charset
	 * @param pfxCertFileInputStream
	 * @return
	 * @throws Exception
	 *
	 *             public static String rsaSign(Map<String, String> params, String charset,
	 *             InputStream pfxCertFileInputStream) throws Exception { String signContent =
	 *             getSignContent(params);
	 *
	 *             return rsaSign(signContent, charset, pfxCertFileInputStream); }
	 */

	public static boolean rsaCheckContent(InputStream publicCertFileInputStream, Map<String, String> params,
			String sign, String charset, String publicKeyPath, boolean isShowLog) throws Exception {
		String content = StringUtils.createLinkString(SignUtils.paraFilter(params));
		return rsaCheckContent(publicCertFileInputStream, content, sign, charset, publicKeyPath);
	}

	public static boolean rsaCheckContent(InputStream publicCertFileInputStream, String content, String sign,
			String charset, String publicKeyPath) throws Exception {
		boolean bFlag = false;
		try {
			Signature signetcheck = Signature.getInstance("SHA1WithRSA");
			signetcheck.initVerify(getPublicKeyFromCert(publicCertFileInputStream, publicKeyPath));
			signetcheck.update(content.getBytes(charset));
			if (signetcheck.verify(Base64Utils.decode(sign))) {
				bFlag = true;
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception("验证签名异常");
		}
		return bFlag;
	}

	public static boolean validateFileSign(FileInputStream fileInputStream, String sign,
			InputStream publicCertFileInputStream, String publicKeyPath) throws Exception {
		boolean result = false;
		// 获得公钥
		PublicKey publicKey = getPublicKeyFromCert(publicCertFileInputStream, publicKeyPath);
		// 构建签名
		Signature signature = Signature.getInstance("SHA1WithRSA");
		signature.initVerify(publicKey);
		byte[] decodedSign = Base64Utils.decode(sign);
		byte[] cache = new byte[CACHE_SIZE];
		int nRead = 0;
		while ((nRead = fileInputStream.read(cache)) != -1) {
			signature.update(cache, 0, nRead);
		}
		fileInputStream.close();
		result = signature.verify(decodedSign);
		return result;
	}

	/**
	 * 读取公钥，x509格式
	 * 
	 * @param password
	 * @param ins
	 * @return
	 * @throws Exception
	 * @see
	 */
	public static PublicKey getPublicKeyFromCert(InputStream ins, String publicKeyPath) throws Exception {
		PublicKey pubKey = (PublicKey) certMap.get(publicKeyPath);
		if (pubKey != null) {
			return pubKey;
		}
		try {
			CertificateFactory cf = CertificateFactory.getInstance("X.509");
			Certificate cac = cf.generateCertificate(ins);
			pubKey = cac.getPublicKey();
			certMap.put(publicKeyPath, pubKey);
		} catch (Exception e) {
			if (ins != null)
				ins.close();
			throw e;
		} finally {
			if (ins != null) {
				ins.close();
			}
		}

		return pubKey;
	}

	/**
	 * 读取PKCS12格式的key（私钥）pfx格式
	 * 
	 * @param password
	 * @param ins
	 * @return
	 * @throws Exception
	 * @see
	 */
	public static PrivateKey getPrivateKeyFromPKCS12(String password, InputStream ins, String privateCerPath)
			throws Exception {
		PrivateKey priKey = null;
		if (certMap.get(privateCerPath) != null) {
			priKey = (PrivateKey) certMap.get(privateCerPath);
			if (priKey != null) {
				return priKey;
			}
		}

		KeyStore keystoreCA = KeyStore.getInstance("PKCS12");
		try {
			// 读取CA根证书
			keystoreCA.load(ins, password.toCharArray());

			Enumeration<?> aliases = keystoreCA.aliases();
			String keyAlias = null;
			if (aliases != null) {
				while (aliases.hasMoreElements()) {
					keyAlias = (String) aliases.nextElement();
					// 获取CA私钥
					priKey = (PrivateKey) (keystoreCA.getKey(keyAlias, password.toCharArray()));
					if (priKey != null) {
						certMap.put(privateCerPath, priKey);
						break;
					}
				}
			}
		} catch (Exception e) {
			if (ins != null)
				ins.close();
			throw e;
		} finally {
			if (ins != null) {
				ins.close();
			}
		}

		return priKey;
	}

	public static byte[] encrypt(Key key, byte[] data) throws Exception {
		try {
			Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
			cipher.init(Cipher.ENCRYPT_MODE, key);
			return cipher.doFinal(data);
		} catch (Exception e) {
			throw e;
		}
	}

	public static byte[] decrypt(Key Key, byte[] data) throws Exception {
		try {
			Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
			cipher.init(Cipher.DECRYPT_MODE, Key);
			return cipher.doFinal(data);
		} catch (Exception e) {
			throw e;
		}
	}

	public static void getCerInfo(String file) throws CertificateException, FileNotFoundException {
		CertificateFactory cf = CertificateFactory.getInstance("X.509");
		X509Certificate cert = (X509Certificate) cf.generateCertificate(new FileInputStream(file));
		PublicKey publicKey = cert.getPublicKey();
		String publicKeyString = Base64Utils.encode(publicKey.getEncoded());
		System.out.println("-----------------公钥--------------------");
		System.out.println(publicKeyString);
		System.out.println("-----------------公钥--------------------");
	}

	public static void main(String[] args) {
		try {
			String privateCerPath = "E:\\mptest\\yulong_666.pfx";
			File file = new File(privateCerPath);
			InputStream pfxCertFileInputStream = new FileInputStream(file);
			// 遍历以及根据重新排序
			System.out.println(rsaSign("11", "UTF-8", "123456", pfxCertFileInputStream, privateCerPath));
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}
